package com.cloudHouse.builder;

import com.cloudHouse.mapping.ParameterMapping;
import com.cloudHouse.mapping.SqlSource;
import com.cloudHouse.parsing.GenericTokenParser;
import com.cloudHouse.parsing.TokenHandler;
import com.cloudHouse.reflection.MetaClass;
import com.cloudHouse.reflection.MetaObject;
import com.cloudHouse.session.Configuration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * sql源码构建器
 */
public class SqlSourceBuilder extends BaseBuilder {

    private static Logger logger = LoggerFactory.getLogger(SqlSourceBuilder.class);

    private static final String parameterProperties = "javaType,jdbcType,mode,numericScale,resultMap,typeHandler,jdbcTypeName";

    public SqlSourceBuilder(Configuration configuration) {
        super(configuration);
    }

    /**
     * 解析源sql语句用于获取sqlSource里面有所有sql语句的要素
     */
    public SqlSource parse(String originalSql, Class<?> parameterType, Map<String, Object> additionalParameters) {
        /**用于设置sql中的？参数的处理器**/
        ParameterMappingTokenHandler handler = new ParameterMappingTokenHandler(configuration, parameterType, additionalParameters);
        /**生成普通记号解析器，处理#{}和${}参数**/
        GenericTokenParser parser = new GenericTokenParser("#{", "}", handler);

        String sql = parser.parse(originalSql);
        // 返回静态 SQL
        return new StaticSqlSource(configuration, sql, handler.getParameterMappings());
    }

    private static class ParameterMappingTokenHandler extends BaseBuilder implements TokenHandler {
        /**
         * 有三个成员变量：参数集合，参数类型，参数元对象（用于执行反射，其实就是自己定义的javabean对象进行操作）
         */
        private List<ParameterMapping> parameterMappings = new ArrayList<>();
        private Class<?> parameterType;
        private MetaObject metaParameters;

        public ParameterMappingTokenHandler(Configuration configuration, Class<?> parameterType, Map<String, Object> additionalParameters) {
            super(configuration);
            this.parameterType = parameterType;
            this.metaParameters = configuration.newMetaObject(additionalParameters);
        }

        public List<ParameterMapping> getParameterMappings() {
            return parameterMappings;
        }

        /**
         * 将content添加到参数集合中，并返回一个？
         * @param content
         * @return
         */
        @Override
        public String handleToken(String content) {
            parameterMappings.add(buildParameterMapping(content));
            return "?";
        }

        // 构建参数映射
        private ParameterMapping buildParameterMapping(String content) {
            // 先解析参数映射,就是转化成一个 HashMap | #{favouriteSection,jdbcType=VARCHAR}
            /**
             * 新建一个参数表达式
             */
            Map<String, String> propertiesMap = new ParameterExpression(content);
            /**获取属性的value**/
            String property = propertiesMap.get("property");
            Class<?> propertyType;
            /**先看看类型注册机有没有对应的参数类型**/
            if (typeHandlerRegistry.hasTypeHandler(parameterType)) {
                propertyType = parameterType;
            } else if (property != null) {
                /**若没有就获取对应的反射器**/
                MetaClass metaClass = MetaClass.forClass(parameterType);
                //开始利用反射进行赋值
                if (metaClass.hasGetter(property)) {
                    propertyType = metaClass.getGetterType(property);
                } else {
                    propertyType = Object.class;
                }
            } else {
                propertyType = Object.class;
            }
            //增加ParameterMapping
            ParameterMapping.Builder builder = new ParameterMapping.Builder(configuration, property, propertyType);
            return builder.build();
        }

    }

}